/**
 * Created with IntelliJ IDEA.
 * User: ajhin
 * Date: 11/15/13
 * Time: 8:45 AM
 * To change this template use File | Settings | File Templates.
 */
package societyGames.codeAlong.model.errorChecking
{
import com.societyGames.system.EventObject;
import com.societyGames.system.FileCache;

import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;

import societyGames.codeAlong.model.Case;
import societyGames.codeAlong.model.Module;
import societyGames.codeAlong.model.ModulesDocument;
import societyGames.xmlFragment.XMLFragmentEditList;

public class LibraryChecker extends EventDispatcher
{
  private var _modulesDocument:ModulesDocument;
  private var _modules:XMLFragmentEditList;
  private var _moduleIndex:int;
  private var _caseIndex:int;
  private var _checkCompleteEventObject:EventObject;
  private var _fileCache:FileCache = new FileCache();
  private var _errors:Vector.<String> = new Vector.<String>();

  private var _codeExerciseApplicationDomain:ApplicationDomain;
  private var _codeExerciseLoader:Loader;

  public function LibraryChecker(modulesDocument:ModulesDocument)
  {
    this._checkCompleteEventObject = new EventObject(this, "CHECK_COMPLETE", Event);
    _modulesDocument = modulesDocument;
    _modules = _modulesDocument.modulesContainer.modules;
  }

  public function get errors():Vector.<String>
  {
    return _errors;
  }

  public function get checkCompleteEventObject():EventObject
  {
    return this._checkCompleteEventObject;
  }

  public function checkLibrary():void
  {
    _moduleIndex = -1;
    checkNextModule();
  }

  private function checkNextModule():void
  {
    _moduleIndex++;
    if (_moduleIndex >= _modules.length)
    {
      _checkCompleteEventObject.dispatchEvent();
      return;
    }
    _caseIndex = -1;
    checkNextCase();
  }

  private function checkNextCase():void
  {
    _caseIndex++;
    var module:Module = currentModule;
    if (_caseIndex >= module.cases.length)
    {
      checkNextModule();
    }
    else
    {
      checkModule(module, _caseIndex);
    }
  }

  private function checkModule(module:Module, caseIndex:int):void
  {
    //Start the load
    var case_:Case = currentCase;
    _fileCache.load("C:/Users/ajhin/Documents/projects/CodeAlong/Out/" + case_.swf, onSWFLoaded, onSWFLoadError);
  }

  private function onSWFLoaded(url:String, byteArray:ByteArray):void
  {
    //Create our own application domain for the case code.
    _codeExerciseApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
    var caseLoaderContext:LoaderContext = new LoaderContext(false, _codeExerciseApplicationDomain);
    caseLoaderContext.allowCodeImport = true; //For editor.

    this._codeExerciseLoader = new Loader();
    //Listen for everything we need
    //_codeExerciseLoader.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, caseUncaughtErrorHandler);
    _codeExerciseLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCodeExerciseLoadComplete, false, 0, true);
    //Do the actual load of the case.
    _codeExerciseLoader.loadBytes(byteArray, caseLoaderContext);
  }

  private function onSWFLoadError(url:String):void
  {
    _errors.push("SWF missing: " + url);
    checkNextCase();
  }

  private function onCodeExerciseLoadComplete(event:Event):void
  {
    _codeExerciseLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCodeExerciseLoadComplete);
    _codeExerciseLoader = null;

    var module:Module = currentModule;
    for each(var functionData:societyGames.codeAlong.model.Function in module.library.functions)
    {
      try
      {
        _codeExerciseApplicationDomain.getDefinition(functionData.name);
      }
      catch (referenceError:ReferenceError)
      {
        _errors.push("Function missing: " + module.id + " " + module.name + " " + functionData.name);
      }
    }
    _codeExerciseApplicationDomain = null;
    checkNextCase();
  }

  private function get currentModule():Module
  {
    return Module(_modules[_moduleIndex]);
  }

  private function get currentCase():Case
  {
    return Case(currentModule.cases[_caseIndex]);
  }
}
}
